package LiuYun

import spinal.core._
import spinal.lib._

import scala.collection.mutable.ArrayBuffer
class CsrRW extends Bundle with IMasterSlave{
    val en:Bool = Bool()
    val a :UInt = UInt(14 bits)
    val rd:UInt = LISA.GPR
    val wd:UInt = LISA.GPR 
    val wm:UInt = LISA.GPR 
    val llbit:Bool = Bool()
    override def asMaster():Unit = {
        out(en,a,wd,wm)
        in (rd,llbit)
    }
}
abstract class CsrFieldInfo(
    val msb:Int,
    val lsb:Int,
    val mode:String,
    val value:Option[Int]=None
){
    def getRange:Range = msb downto lsb
    def getDocStr():String = {
        val name = data.getPartialName
        val fname = name.substring(name.lastIndexOf('_') + 1)
        val doc_str = fname.toUpperCase + ":" + mode.toUpperCase
        if(value.isEmpty)
            return doc_str
        return doc_str + "=" + value.get.toString
    }
    val data:BaseType
    def getUInt:UInt
    def getNext(rw:CsrRW):UInt
    def assignedFrom(we:Bool,rw:CsrRW):Unit
    def getReadData:UInt = if(mode.charAt(0) == 'r') getUInt else U(0)
}
class CsrFieldUInt(val data:UInt,msb:Int,lsb:Int,mode:String,value:Option[Int]) extends CsrFieldInfo(msb,lsb,mode,value){
    def getUInt:UInt = data
    def getNext(rw:CsrRW):UInt = {
        val bits:Range = msb downto lsb
        rw.wd(bits) & rw.wm(bits) | data & ~rw.wm(bits)
    }
    def assignedFrom(we:Bool,rw:CsrRW):Unit = {
        mode match {
        case "rw" =>
            when(we){
                data := getNext(rw)
            }
        case _ =>
        }
    }
}
class CsrFieldBool(val data:Bool,val loc:Int,mode:String,value:Option[Boolean]) extends CsrFieldInfo(loc,loc,mode,value.map(_.toInt)){
    def getUInt:UInt = data.asUInt
    def getNext(rw:CsrRW):UInt = Mux(rw.wm(loc),rw.wd(loc),data).asUInt
    def assignedFrom(we:Bool,rw:CsrRW):Unit = {
        mode match {
        case "rw" => 
            when(we && rw.wm(loc)){
                data := rw.wd(loc)
            }
        case "w1" =>
            data := we && rw.wm(loc) && rw.wd(loc)
        case _ =>
        }
    }
}
case class CsrUpdate(csr:Csr
                    ,wb:CsrWb
                    ,tlbrd:TlbRdRes
                    ,tlbsrch:TlbSrchRes
                    ,rw:CsrRW) extends Bundle
class CsrEntry(val id:Int,val passed:Boolean=false) extends Bundle{
    def getClsName = this.getClass().getName()
    def getCsrName = {
        val cls_name = getClsName
        cls_name.substring(cls_name.lastIndexOf('.') + 4)
    }
    val fields = new ArrayBuffer[CsrFieldInfo]()
    private var sorted:ArrayBuffer[CsrFieldInfo] = null
    var we:Bool=if(passed) null else Bool()
    var hit:Bool=if(passed) null else Bool()
    var value:UInt=null
    def isReg(mode:String):Boolean = {
        mode match {
            case "rr" => false
            case "rw" => true
            case "w1" => false
            case "r"  => true
        }
    }
    private def wrapData(dtype:UInt,mode:String,value:Option[UInt]):UInt={
        val is_reg:Boolean = isReg(mode)
        if(!is_reg){
            if(value.nonEmpty)
                dtype := value.get
            return dtype
        }
        if(value.nonEmpty)
            return Reg(dtype) init value.get
        return Reg(dtype)
    }
    private def wrapData(dtype:Bool,mode:String,value:Option[Bool]):Bool={
        val is_reg:Boolean = isReg(mode)
        if(!is_reg){
            if(value.nonEmpty)
                dtype := value.get
            return dtype
        }
        if(value.nonEmpty)
            return Reg(dtype) init value.get
        return Reg(dtype)
    }
    protected def addField(msb:Int,lsb:Int,mode:String,v:Option[Int]):UInt = {
        val w:Int = msb - lsb + 1
        val data:UInt = if(passed) UInt(w bits) else wrapData(UInt(w bits),mode,v.map(U(_)))
        fields.append(new CsrFieldUInt(data,msb,lsb,mode,v))
        sorted = null
        return data
    }
    protected def addField(loc:Int,mode:String,v:Option[Boolean]):Bool = {
        val data:Bool = if(passed) Bool() else wrapData(Bool(),mode,v.map(Bool(_)))
        fields.append(new CsrFieldBool(data,loc,mode,v))
        sorted = null
        return data
    }
    protected def addField    ():UInt = addField(LISA.w_gpr - 1, 0, "rw", None)
    protected def addField    (msb:Int,lsb:Int      ):UInt = addField(msb,lsb,"rw",None)
    protected def addFieldRO  (msb:Int,lsb:Int      ):UInt = addField(msb,lsb,"r" ,None)
    protected def addFieldUInt(msb:Int,lsb:Int      ):UInt = addField(msb,lsb,"rr",None)
    protected def addFieldInit(msb:Int,lsb:Int,v:Int):UInt = addField(msb,lsb,"rw",Some(v))
    protected def addFieldZero(msb:Int,lsb:Int      ):UInt = addField(msb,lsb,"rw",Some(0))
    protected def addFieldW1  (loc:Int):Bool = addField(loc,"w1",None)
    protected def addField    (loc:Int):Bool = addField(loc,"rw",None)
    protected def addFieldRO  (loc:Int):Bool = addField(loc,"r" ,None)
    protected def addFieldUInt(loc:Int):Bool = addField(loc,"rr",None)
    protected def addFieldInit(loc:Int,v:Boolean):Bool = addField(loc,"rw",Some(v))
    protected def addFieldZero(loc:Int):Bool = addField(loc,"rw",Some(false))
    def setHit(rw:CsrRW):Unit = {
        hit := rw.a === U(this.id)
    }
    def setWe(rw:CsrRW):Unit = {
        we := rw.en && hit
    }
    def writeBy(rw:CsrRW):Unit = {
        fields.foreach(_.assignedFrom(we,rw))
    }
    def sortFields():Unit = {
        if(sorted == null){
            sorted = fields.filter(_.mode != "w1").sortBy(_.lsb)
        }
    }
    def getBlanks():ArrayBuffer[(Int,Int)] = {
        sortFields
        val blanks = new ArrayBuffer[(Int,Int)]()
        val n = sorted.length
        for(i <- 0 to n){
            val lsb = if(i > 0) sorted(i-1).msb + 1 else 0
            val msb = if(i < n) sorted(i  ).lsb - 1 else LISA.w_gpr - 1
            if(lsb <= msb){
                blanks.append((msb,lsb))
            }
        }
        return blanks
    }
    def getValue():UInt = {
        sortFields
        if(value == null){
            value =  LISA.GPR
            for(i <- 0 until sorted.length){
                value(sorted(i).getRange) := sorted(i).getReadData
            }
            for((msb,lsb) <- getBlanks){
                value(msb downto lsb) := U(0)
            }
        }
        return value
    }
    def receive(env:CsrUpdate):Unit = {}
    def fieldAt(lsb:Int):CsrFieldInfo = fields.find(_.lsb == lsb).get
}
class CsrCRMD(passed:Boolean=true) extends CsrEntry(0x0,passed){
    val plv :UInt = addFieldZero( 1, 0)
    val ie  :Bool = addFieldZero( 2)
    val da  :Bool = addFieldInit( 3, true)
    val pg  :Bool = addFieldZero( 4)
    val datf:UInt = addFieldZero( 6, 5)
    val datm:UInt = addFieldZero( 8, 7)
    override def receive(env:CsrUpdate):Unit = {
        when(env.wb.ex){
            plv := U(0)
            ie  := False
        }.elsewhen(env.wb.ertn){
            plv := env.csr.prmd.pplv
            ie  := env.csr.prmd.pie
        }
        when(env.wb.isRefill){
            da := True
            pg := False
        }.elsewhen(env.wb.ertn && env.csr.estat.ecode === LISA.Ex.TLBR.code){
            da := False
            pg := True
        }
    }
}
class CsrPRMD  extends CsrEntry(0x1){
    val pplv:UInt = addField( 1, 0)
    val pie :Bool = addField(    2)
    override def receive(env:CsrUpdate):Unit = {
        when(env.wb.ex){
            pplv := env.csr.crmd.plv
            pie  := env.csr.crmd.ie
        }
    }
}
class CsrEUEN  extends CsrEntry(0x2){
    val fpe :Bool = addField(    0)
}
class CsrECFG  extends CsrEntry(0x4){
    val lie :UInt = addFieldZero(12, 0)
}
class CsrESTAT(passed:Boolean=true) extends CsrEntry(0x5,passed){
    val is_sw   :UInt = addFieldZero( 1, 0)
    val is_hw   :UInt = addFieldRO  (12, 2)
    val ecode   :UInt = addFieldRO  (21,16)
    val esubcode:UInt = addFieldRO  (30,22)
    def getTI:Bool = is_hw(9)
    def getIS:UInt = is_hw @@ is_sw
    override def receive(env:CsrUpdate):Unit = {
        when(env.wb.ex){
            ecode    := env.wb.ecode
            esubcode := env.wb.esubc
        }
        // 7-0 for interuptions
        is_hw(8) := False // performance counter overflow
        //  9 for ti
        // 10 for ipi
    }
}
class CsrERA   extends CsrEntry(0x6){
    val pc:UInt = addField()
    override def receive(env:CsrUpdate):Unit = {
        when(env.wb.ex){
            pc := env.wb.pc
        }
    }
}
class CsrBADV  extends CsrEntry(0x7){
    val vaddr:UInt = addField()
    val related = Bool()
    override def receive(env:CsrUpdate):Unit = {
        related := env.wb.isRefill || env.wb.isMemEx
        when(related){
            vaddr := env.wb.va
        }
    }
}
class CsrEENTRY extends CsrEntry(0xc){
    val va  :UInt  = addField(31, 6)
}
class CsrTLBIDX(passed:Boolean=true) extends CsrEntry(0x10,passed){
   val index:UInt = addField(LISA.w_tlbidx-1,0)
   val ps   :UInt = addField(29,24)
   val ne   :Bool = addField(   31)
    override def receive(env:CsrUpdate):Unit = {
        when(env.tlbsrch.valid && env.tlbsrch.hit){
            index := env.tlbsrch.index
            ne    := !env.tlbsrch.hit
        }.elsewhen(env.tlbsrch.valid){
            ne    := !env.tlbsrch.hit
        }.elsewhen(env.tlbrd.valid){
            env.tlbrd.wrapWrite(this,env.tlbrd.dat)
            ne    := !env.tlbrd.e
        }
    }
}
class CsrTLBEHI(passed:Boolean=true) extends CsrEntry(0x11,passed){
    val vppn:UInt = addField(31,13)
    val related:Bool = if(passed) null else Bool()
    override def receive(env:CsrUpdate):Unit = {
        related := env.wb.isRefill || env.wb.isTlbEx
        when(related){
            vppn := env.wb.va(31 downto 13)
        }.elsewhen(env.tlbrd.valid){
            env.tlbrd.wrapWrite(this,env.tlbrd.dat)
        }
    }
}
class CsrTLBELONoG(val my_id:Int=0,passed:Boolean=true) extends CsrEntry(0x12+my_id,passed){
    val v  :Bool  = addField(    0)
    val d  :Bool  = addField(    1)
    val plv:UInt  = addField( 3, 2)
    val mat:UInt  = addField( 5, 4)
    val ppn:UInt  = addField(LISA.w_ppn+7, 8)
    def cleared:Unit = {
        v   := False
        d   := False
        plv := U(0)
        mat := U(0)
        ppn := U(0)
    }
}
class CsrTLBELO(my_id:Int=0,passed:Boolean=true) extends CsrTLBELONoG(my_id,passed){
    val g :Bool   = addField(    6)
    override def receive(env:CsrUpdate):Unit = {
        when(env.tlbrd.valid){
            env.tlbrd.wrapWrite(this,env.tlbrd.dat.lo(my_id))
        }
    }
    override def cleared:Unit = {
        super.cleared
        g := False
    }
}
class CsrASID(passed:Boolean=true) extends CsrEntry(0x18,passed){
    val asid    :UInt = addField    (LISA.w_asid-1,0)
    val asidbits:UInt = addFieldUInt(23,16)
    override def receive(env:CsrUpdate):Unit = {
        asidbits := U(LISA.w_asid)
        when(env.tlbrd.valid){
            env.tlbrd.wrapWrite(this,env.tlbrd.dat)
        }
    }
}
class CsrPGDHL(val my_id:Int=0) extends CsrEntry(0x19+my_id){
    val base:UInt = addField(31,12)
}
class CsrPGD extends CsrEntry(0x1b){
    val base:UInt = addFieldUInt(31,12)
    override def receive(env:CsrUpdate):Unit = {
        base := Mux(env.csr.badv.vaddr.msb,env.csr.pgdh.base,env.csr.pgdl.base)
    }
}
class CsrCPUID   extends CsrEntry(0x20){
    val coreid = addFieldUInt( 8, 0)
}
class CsrSAVE(id:Int) extends CsrEntry(0x30+id){
    val data = addField()
}
class CsrTID   extends CsrEntry(0x40){
    val tid = addField()
}
class CsrTCFG  extends CsrEntry(0x41){
    val en       = addFieldZero(             0)
    val periodic = addFieldZero(             1)
    val initval  = addField    (LISA.w_gpr-1,2)
    val stop = Reg(Bool())
    override def receive(env:CsrUpdate):Unit = {
        val finish:Bool = env.csr.tcfg.en && !env.csr.tval.hasRemain && !env.csr.tcfg.periodic
        when(finish){
            stop := True
        }
        when(env.csr.tcfg.we){
            stop := !env.rw.wd(0)
        }
    }
}
class CsrTVAL  extends CsrEntry(0x42){
    val timeval  = addFieldRO(LISA.w_gpr-1,0)
    def hasRemain:Bool = timeval =/= U(0)
    override def receive(env:CsrUpdate):Unit = {
        when(env.csr.tcfg.we){
            timeval := env.csr.tcfg.fieldAt(2).getNext(env.rw) << 2
        }.elsewhen(env.csr.tcfg.en){
            when(hasRemain){
                timeval := timeval - 1
            }.elsewhen(env.csr.tcfg.periodic){
                timeval := env.csr.tcfg.initval << 2
            }
        }
        val ti = env.csr.estat.getTI
        when(env.csr.tcfg.en && !hasRemain && !env.csr.tcfg.stop){
            ti := True
        }.elsewhen(env.csr.ticlr.clr){
            ti := False
        }
    }
}
class CsrTICLR extends CsrEntry(0x44){
    val clr = addFieldW1(0)
}
class CsrLLBCTL extends CsrEntry(0x60){
    val rollb = addFieldRO(0)
    val wcllb = addFieldW1(1)
    val klo   = addField  (2)
    override def receive(env:CsrUpdate):Unit = {
        when(env.wb.ertn){
            klo := False
        }
        when(env.wb.ll && !env.wb.ex){
            rollb := True
        }.elsewhen(wcllb || env.wb.ertn && !klo || env.wb.sc){
            rollb := False
        }
    }
}
class CsrTLBRENTRY extends CsrEntry(0x88){
    val pa = addField(31, 6)
}
class CsrCTAG extends CsrEntry(0x98){
    val data = addField()
}
class CsrDMW(val my_id:Int=0,passed:Boolean=true) extends CsrEntry(0x180+my_id,passed){
    val plv0 = addField(    0)
    val plv3 = addField(    3)
    val mat  = addField( 5, 4)
    val pseg = addField(27,25)
    val vseg = addField(31,29)
    var en:Bool=null
    def checkEnabled(plv:UInt):Bool = {
        // plv cannot be different value in the same cycle 
        if(en != null)return en
        en = plv0 && plv === U(0) || plv3 && plv === U(3)
        return en
    }
    def translate(va:UInt):UInt = {
        pseg @@ va(28 downto 0)
    }
    def compare(va:UInt,plv:UInt):Bool = {
        checkEnabled(plv)
        en && va(31 downto 29) === vseg
    }
}
class Csr extends Bundle{
    val stable_timer = RegInit(U(0,64 bits))
    stable_timer := stable_timer + 1
    val entries = new ArrayBuffer[CsrEntry]()
    def readBy(rw:CsrRW){
        rw.rd := MuxOH.or(entries.map(_.hit),entries.map(_.getValue))
    }
    def writeBy(rw:CsrRW){
        entries.foreach(_.setHit(rw))
        entries.foreach(_.setWe(rw))
        entries.foreach(_.writeBy(rw))
    }
    def receive(env:CsrUpdate):Unit = {
        for(entry <- entries){
            entry.receive(env)
        }
    }
    def addEntry[T<:CsrEntry](e:T):T = {
        entries.append(e)
        return e
    }
    val crmd     :CsrCRMD      = addEntry(new CsrCRMD     (false)  ) // basic CSR
    val prmd     :CsrPRMD      = addEntry(new CsrPRMD              )
    val euen     :CsrEUEN      = addEntry(new CsrEUEN              )
    val ecfg     :CsrECFG      = addEntry(new CsrECFG              )
    val estat    :CsrESTAT     = addEntry(new CsrESTAT    (false)  )
    val era      :CsrERA       = addEntry(new CsrERA               )
    val badv     :CsrBADV      = addEntry(new CsrBADV              )
    val eentry   :CsrEENTRY    = addEntry(new CsrEENTRY            )  
    val cpuid    :CsrCPUID     = addEntry(new CsrCPUID             )
    val save0    :CsrSAVE      = addEntry(new CsrSAVE     (0)      )
    val save1    :CsrSAVE      = addEntry(new CsrSAVE     (1)      )
    val save2    :CsrSAVE      = addEntry(new CsrSAVE     (2)      )
    val save3    :CsrSAVE      = addEntry(new CsrSAVE     (3)      )
    val tlbidx   :CsrTLBIDX    = addEntry(new CsrTLBIDX   (  false)) // MMU related
    val tlbehi   :CsrTLBEHI    = addEntry(new CsrTLBEHI   (  false))
    val tlbelo0  :CsrTLBELO    = addEntry(new CsrTLBELO   (0,false))
    val tlbelo1  :CsrTLBELO    = addEntry(new CsrTLBELO   (1,false))
    val asid     :CsrASID      = addEntry(new CsrASID     (  false))
    val pgdl     :CsrPGDHL     = addEntry(new CsrPGDHL    (0)      )
    val pgdh     :CsrPGDHL     = addEntry(new CsrPGDHL    (1)      )
    val pgd      :CsrPGD       = addEntry(new CsrPGD               )
    val dmw0     :CsrDMW       = addEntry(new CsrDMW      (0,false))
    val dmw1     :CsrDMW       = addEntry(new CsrDMW      (1,false))
    val tlbrentry:CsrTLBRENTRY = addEntry(new CsrTLBRENTRY         )
    val tid      :CsrTID       = addEntry(new CsrTID               ) // Timer related
    val tcfg     :CsrTCFG      = addEntry(new CsrTCFG              )
    val tval     :CsrTVAL      = addEntry(new CsrTVAL              )
    val ticlr    :CsrTICLR     = addEntry(new CsrTICLR             )
    val llbctl   :CsrLLBCTL    = addEntry(new CsrLLBCTL            ) // other
    val ctag     :CsrCTAG      = addEntry(new CsrCTAG              )
    def connect(core:CoreIn){
       cpuid.coreid := core.id
       estat.is_hw(7 downto 0) := core.intr
       estat.is_hw(10) := core.ipi
    }
}
class CsrFile extends Component{
    val io = new Bundle{
        val rw    = slave(new CsrRW)
        val wb    = in (new CsrWb)
        val core  = in (new CoreIn    )
        val exbus = out(new CoreCancel)
        val totlb = out(new TlbCsr)
        val tofe  = out(new FeCsr)
        val tode  = out(new DeCsr)
        val toex  = out(new ExCsr)
        val tlbrd = in (new TlbRdRes)
        val tlbsrch = in(new TlbSrchRes)
        val difftest = out(new DiffCsrreg)
    }
    val csr = new Csr()
    val env = new CsrUpdate(csr,io.wb,io.tlbrd,io.tlbsrch,io.rw)
    csr.readBy(io.rw)
    csr.writeBy(io.rw)
    io.wb.gen_cancel(csr,io.exbus)
    io.exbus.ghr := B(0) //NEED TODO
    csr.receive(env)
    csr.connect(io.core)
    io.totlb.collect(csr)
    io.tofe.collect(csr)
    io.tode.collect(csr)
    io.toex.collect(csr)
    io.difftest.collect(csr)
    io.difftest.coreid := B(0,8 bits)
    io.rw.llbit := csr.llbctl.getValue()(0)
}

object GenerateVerilogForCsr {
    import org.apache.poi.ss.util.CellRangeAddress
    import org.apache.poi.ss.usermodel.BorderStyle
    import org.apache.poi.ss.usermodel.IndexedColors
    import org.apache.poi.ss.usermodel.CellStyle
    import org.apache.poi.ss.usermodel.HorizontalAlignment
    import org.apache.poi.ss.usermodel.VerticalAlignment
    import org.apache.poi.ss.usermodel.FillPatternType
    import org.apache.poi.xssf.usermodel.XSSFCell
    import org.apache.poi.xssf.usermodel.XSSFRow
    import org.apache.poi.xssf.usermodel.XSSFSheet
    import org.apache.poi.xssf.usermodel.XSSFWorkbook

    import java.io.File
    import java.io.FileOutputStream
    import java.io.IOException

    val path_doc = "./gen/doc/"
    def getBitCol(i:Int) = 34 - i
    val c_orange:Short = IndexedColors.ORANGE.getIndex()
    val c_pink  :Short = IndexedColors.PINK  .getIndex()
    val c_aqua  :Short = IndexedColors.AQUA  .getIndex()
    val c_green :Short = IndexedColors.GREEN .getIndex()
    val c_yellow:Short = IndexedColors.YELLOW.getIndex()
    val c_grey  :Short = IndexedColors.GREY_25_PERCENT.getIndex()
    def getDocStyle(workbook:XSSFWorkbook,color:Short):CellStyle = {
        val style:CellStyle = workbook.createCellStyle()
        style.setAlignment(HorizontalAlignment.CENTER)
        style.setVerticalAlignment(VerticalAlignment.CENTER)
        style.setFillForegroundColor(color)
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND)
        style.setBorderTop   (BorderStyle.THIN)
        style.setBorderBottom(BorderStyle.THIN)
        style.setBorderLeft  (BorderStyle.THIN)
        style.setBorderRight (BorderStyle.THIN)
        return style
    }
    def genDocTitle(workbook:XSSFWorkbook,sheet:XSSFSheet):Unit = {
        val title:XSSFRow   = sheet.createRow(0)
        val s_orange:CellStyle = getDocStyle(workbook,c_orange)
        val l_title:List[String] = List("id","hex","name")
        for(c <- 0 until l_title.length){
            val cell:XSSFCell = title.createCell(c)
            cell.setCellValue(l_title(c))
            cell.setCellStyle(s_orange)
        }
        for(j <- 0 to 31){
            val cell:XSSFCell = title.createCell(getBitCol(j))
            cell.setCellValue(j)
            cell.setCellStyle(s_orange)
        }
    }
    def genDoc(csr:Csr):Unit = {
        val workbook:XSSFWorkbook = new XSSFWorkbook()
        val sheet   :XSSFSheet    = workbook.createSheet("csrdef")
        genDocTitle(workbook,sheet)
        val s_pink   :CellStyle = getDocStyle(workbook,c_pink  )
        val s_yellow :CellStyle = getDocStyle(workbook,c_yellow)
        val s_grey   :CellStyle = getDocStyle(workbook,c_grey  )
        val s_green  :CellStyle = getDocStyle(workbook,c_green )
        val r_style  :CellStyle = workbook.createCellStyle()
        r_style.setBorderTop   (BorderStyle.THIN)
        r_style.setBorderBottom(BorderStyle.THIN)
        r_style.setBorderLeft  (BorderStyle.THIN)
        r_style.setBorderRight (BorderStyle.THIN)
        for(i <- 0 until csr.entries.length){
            val r = i + 1
            val row:XSSFRow = sheet.createRow(r)
            row.setRowStyle(r_style)
            val entry:CsrEntry = csr.entries(i)
            val cell_id  :XSSFCell = row.createCell(0)
            val cell_hex :XSSFCell = row.createCell(1)
            val cell_name:XSSFCell = row.createCell(2)
            cell_id  .setCellValue  (entry.id)
            cell_hex .setCellFormula("DEC2HEX(A"+(r+1).toString+")")
            cell_name.setCellValue  (entry.getCsrName)
            for(field <- entry.fields){
                val (msb,lsb):(Int,Int) = (field.msb,field.lsb)
                val cell_field:XSSFCell = row.createCell(getBitCol(field.msb))
                val cell_style:CellStyle = field.mode match {
                    case "r" => s_yellow
                    case "rr" => s_yellow
                    case "w1" => s_pink
                    case "rw" => s_green
                }
                cell_field.setCellValue(field.getDocStr)
                cell_field.setCellStyle(cell_style)
                if(field.msb > field.lsb)
                    sheet.addMergedRegion(new CellRangeAddress(i+1,i+1,getBitCol(field.msb),getBitCol(field.lsb)))
            }
            for((msb,lsb) <- entry.getBlanks){
                val cell_blank:XSSFCell = row.createCell(getBitCol(msb))
                cell_blank.setCellStyle(s_grey)
                if(msb - lsb > 0){
                    sheet.addMergedRegion(new CellRangeAddress(i+1,i+1,getBitCol(msb),getBitCol(lsb)))
                }
            }
        }
        (new File(path_doc)).mkdir()
        val f = new FileOutputStream(path_doc + "csrdef.xls")
        workbook.write(f)
        f.close()
    }
    def main(args: Array[String]): Unit = {
        val report = SpinalConfig(mode = Verilog, removePruned = true, oneFilePerComponent=true, targetDirectory="./gen/rtl").generate(new CsrFile())
        val top:CsrFile = report.toplevel
        if (args.length > 0 && args(0) == "--with-doc" && top != null){
            genDoc(top.csr)
        }
        args.foreach(println)
    }
}
